package com.aaa.config;

import com.aaa.pojo.DefaultMsg;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * Spring Security的配置类
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsServiceImpl userDetailsService;

    /**
     * 配置 AuthenticationManagerBuilder 身份验证管理器
     * 使用UserDetailsService的接口实现类对象去加载密码信息
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    /**
     * 往Spring容器中放一个PasswordEncoder接口的实现类对象
     * 这样，在Spring Security框架校验密码的时候会自动去使用这个对象
     *
     * @return PasswordEncoder实例
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 配置HttpSecurity
     * 指定登录页面、处理登录请求的路径、默认登录成功的路径、登录成功和失败的处理方式等
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers()
                .permitAll()
                .anyRequest()
                .authenticated();

        http.formLogin()
                .loginPage("/toLogin").permitAll()
                .loginProcessingUrl("/checkUser")
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        Object user = authentication.getPrincipal();
                        DefaultMsg defaultMsg = new DefaultMsg(200, 1, user, null);
                        response.setContentType("application/json;charset=UTF-8");
                        String json = new Gson().toJson(defaultMsg);
                        PrintWriter writer = response.getWriter();
                        writer.print(json);
                        writer.close();
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
                        DefaultMsg defaultMsg = new DefaultMsg(200, 0, null, null);
                        response.setContentType("application/json;charset=UTF-8");
                        String json = new Gson().toJson(defaultMsg);
                        PrintWriter writer = response.getWriter();
                        writer.print(json);
                        writer.close();
                    }
                });
        http.logout().logoutUrl("/toLogout").logoutSuccessUrl("/index/logoutSuccess").permitAll();

        http.csrf().disable();
        http.cors();
    }
}
